package online.foxnull2.foxmall.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import online.foxnull2.common.constant.WareConstant;
import online.foxnull2.foxmall.ware.entity.PurchaseDetailEntity;
import online.foxnull2.foxmall.ware.entity.PurchaseEntity;
import online.foxnull2.foxmall.ware.mapper.PurchaseMapper;
import online.foxnull2.foxmall.ware.service.PurchaseDetailService;
import online.foxnull2.foxmall.ware.service.PurchaseService;
import online.foxnull2.foxmall.ware.service.WareSkuService;
import online.foxnull2.foxmall.ware.utils.PageUtils;
import online.foxnull2.foxmall.ware.utils.Query;
import online.foxnull2.foxmall.ware.vo.MergeVo;
import online.foxnull2.foxmall.ware.vo.purchaseDone.PurchaseDoneItem;
import online.foxnull2.foxmall.ware.vo.purchaseDone.PurchaseDoneVo;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


@Service("purchaseService")
public class PurchaseServiceImpl extends ServiceImpl<PurchaseMapper, PurchaseEntity> implements PurchaseService {

    private final PurchaseDetailService purchaseDetailService;
    private final WareSkuService wareSkuService;

    @Autowired
    public PurchaseServiceImpl(PurchaseDetailService purchaseDetailService,
                               WareSkuService wareSkuService) {
        this.purchaseDetailService = purchaseDetailService;
        this.wareSkuService = wareSkuService;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageUnreceive(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>().eq("status", 0).or().eq("status", 1)
        );

        return new PageUtils(page);
    }

    @Transactional
    @Override
    public void mergePurchase(MergeVo mergeVo) {
        Long purchaseId = mergeVo.getPurchaseId();
        if (ObjectUtils.isEmpty(purchaseId)) {
            PurchaseEntity purchaseEntity = new PurchaseEntity();
            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        }
        PurchaseEntity purchaseEntity = this.getById(purchaseId);

        if (Objects.equals(purchaseEntity.getStatus(), WareConstant.PurchaseStatusEnum.CREATED.getCode()) ||
                Objects.equals(purchaseEntity.getStatus(), WareConstant.PurchaseStatusEnum.ALLOCATED.getCode())) {
            List<Long> items = mergeVo.getItems();
            List<PurchaseDetailEntity> purchaseDetailEntityList = new ArrayList<>();
            for (Long item : items) {
                PurchaseDetailEntity purchaseDetailEntity = new PurchaseDetailEntity();
                purchaseDetailEntity.setId(item)
                        .setPurchaseId(purchaseId)
                        .setStatus(WareConstant.PurchaseDetailStatusEnum.ALLOCATED.getCode());
                purchaseDetailEntityList.add(purchaseDetailEntity);
            }
            purchaseDetailService.updateBatchById(purchaseDetailEntityList);

            this.updateById(new PurchaseEntity().setId(purchaseId).setUpdateTime(new Date()));
        }
    }

    @Transactional
    @Override
    public void received(List<Long> ids) {
        List<PurchaseEntity> purchaseEntityList = ids.stream().map(this::getById).filter(purchaseEntity ->
                        Objects.equals(purchaseEntity.getStatus(), WareConstant.PurchaseStatusEnum.CREATED.getCode()) ||
                                Objects.equals(purchaseEntity.getStatus(), WareConstant.PurchaseStatusEnum.ABNORMAL.getCode()))
                .map(purchaseEntity -> purchaseEntity
                        .setStatus(WareConstant.PurchaseStatusEnum.RECEIVED.getCode())
                        .setUpdateTime(new Date()))
                .collect(Collectors.toList());
        this.updateBatchById(purchaseEntityList);

        purchaseEntityList.forEach(purchaseEntity -> {
            List<PurchaseDetailEntity> purchaseDetailEntityList = purchaseDetailService.list(new QueryWrapper<PurchaseDetailEntity>()
                    .eq("purchase_id", purchaseEntity.getId()));
            purchaseDetailEntityList.forEach(purchaseDetailEntity -> purchaseDetailEntity
                    .setStatus(WareConstant.PurchaseDetailStatusEnum.PURCHASING.getCode()));
            purchaseDetailService.updateBatchById(purchaseDetailEntityList);
        });
    }

    @Transactional
    @Override
    public void done(PurchaseDoneVo purchaseDoneVo) {
        AtomicReference<Boolean> purchaseStatus = new AtomicReference<>(true);

        List<PurchaseDoneItem> purchaseDoneItemList = purchaseDoneVo.getItems();
        List<PurchaseDetailEntity> purchaseDetailEntityList = purchaseDoneItemList.stream().map(purchaseDoneItem -> {
            if (Objects.equals(purchaseDoneItem.getStatus(), WareConstant.PurchaseDetailStatusEnum.FAILED.getCode())) {
                purchaseStatus.set(false);
            } else {
                PurchaseDetailEntity purchaseDetailEntity = purchaseDetailService.getById(purchaseDoneItem.getItemId());
                if (ObjectUtils.isNotEmpty(purchaseDetailEntity)) {
                    wareSkuService.addStock(purchaseDetailEntity.getSkuNum(), purchaseDetailEntity.getSkuId(), purchaseDetailEntity.getWareId());
                }
            }

            return new PurchaseDetailEntity().setId(purchaseDoneItem.getItemId())
                    .setStatus(purchaseDoneItem.getStatus());
        }).collect(Collectors.toList());
        purchaseDetailService.updateBatchById(purchaseDetailEntityList);

        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseDoneVo.getId())
                .setStatus(purchaseStatus.get() ? WareConstant.PurchaseStatusEnum.COMPLETED.getCode() :
                        WareConstant.PurchaseStatusEnum.ABNORMAL.getCode());
        this.updateById(purchaseEntity);
    }

}